package Overlapping;

import graphguide.GeneralValueNode;
import graphguide.GraphGuide;
import graphguide.GraphNode;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.PriorityQueue;

import knowledgebase.QueryYAGOTDB;
import customization.Constants;
import dataguide.DataGuide;
import dataguide.PathPair;
import dataguide.ValueNode;

public class OverlappingGuides {

	public static int NumberofInputvalues = 0;
	GraphGuide graphG = null;
	DataGuide dataG = null;

	/**
	 * several comparators can be used => Clement's methods, simple string
	 * comparator
	 **/
	Comparator<GeneralValueNode> c = null;

	/** stores the results **/
	public HashSet<PathPair> pathPairsSet;

	public OverlappingGuides(GraphGuide graphG, DataGuide dataG,
			Comparator<GeneralValueNode> c) {
		this.graphG = graphG;
		this.dataG = dataG;

		pathPairsSet = new HashSet<PathPair>();
		this.c = c;

		overlapping(c);
	}

	public void overlapping(Comparator<GeneralValueNode> c) {
		PriorityQueue<GraphNode> pq1 = graphG
				.getValuesInAPriorityQueue(new GraphNode.NormalizeCompare());
		PriorityQueue<ValueNode> pq2 = dataG
				.getValuesInAPriorityQueue(new ValueNode.NormalizedCompare());

		// for(GraphNode g : pq1){
		// System.out.println(g.normalizedName);
		// }
		// System.out.println("\n\n\n\n\n\nDATA GUIDE!!!!!!\n\n\n");
		// for(ValueNode v : pq2){
		// System.out.println(v.normalizedValue);
		// }

		HashSet<PathPair> processedPaths = new HashSet<PathPair>();

		while (!pq1.isEmpty() && !pq2.isEmpty()) {
			GraphNode peek1 = pq1.peek();
			ValueNode peek2 = pq2.peek();
			int comp = c.compare(peek1, peek2);
			if (comp < 0) {
				pq1.poll();
				/** System.out.println("Value q1: "+vn.value); **/
			} else if (comp > 0) {
				pq2.poll();
				/** System.out.println("Value q2: "+vn.value); **/
			} else {
				/**
				 * since there might be several nodes with the same value, we
				 * treat the problem for the general case
				 **/
				System.out.println("Overlapping detected:  value="
						+ peek2.normalizedValue);
				ArrayList<GraphNode> list1 = new ArrayList<>();
				list1.add(pq1.poll());
				while (!pq1.isEmpty()
						&& c.compare(pq1.peek(), list1.get(0)) == 0) {
					list1.add(pq1.poll());
				}

				ArrayList<ValueNode> list2 = new ArrayList<>();
				list2.add(pq2.poll());
				while (!pq2.isEmpty()
						&& c.compare(pq2.peek(), list2.get(0)) == 0) {
					list2.add(pq2.poll());
				}

				System.out.println("\t occurs in GraphGuide " + list1.size()
						+ " times and occurs in DataGuide " + list2.size()
						+ " times\n");
				processPathPairs(list1, list2, pathPairsSet, processedPaths);
			}
		}

	}

	public void processPathPairs(ArrayList<GraphNode> list1,
			ArrayList<ValueNode> list2, HashSet<PathPair> pathPairsCount,
			HashSet<PathPair> processedPaths) {
		for (GraphNode gn1 : list1)
			for (ValueNode n2 : list2) {
				String p1 = gn1.relationPathFromParent;
				String p2 = n2.parent.getStringPathRootToNode();
				PathPair pair = new PathPair(p1, p2);
				if (processedPaths.contains(pair)) {
				} // return;
				else
					processedPaths.add(pair);

				if (!pathPairsCount.contains(pair)) {
					pathPairsCount.add(pair);
				}
				// else {
				// int count=pathPairsCount.get(pair);
				// pathPairsCount.put(pair, new Integer(count+1));
				// }

			}
	}

	/********************************************************************************/
	/****** Print Priority Queue ********************/
	/*******************************************************************************/
	public void checkPriorityQueues() {
		PriorityQueue<GraphNode> pq1 = graphG
				.getValuesInAPriorityQueue(new GraphNode.NormalizeCompare());
		PriorityQueue<ValueNode> pq2 = dataG
				.getValuesInAPriorityQueue(new ValueNode.NormalizedCompare());

		while (!pq1.isEmpty()) {
			System.out.println(pq1.poll().normalizedName);
		}

		System.out.println("\n\nDATA GUIDE \n\n");

		while (!pq2.isEmpty()) {
			System.out.println(pq2.poll().normalizedValue);
		}

	}

	public void printPathPairsCount() {
		for (PathPair pp : pathPairsSet) {
			System.out.println("Path GG: " + pp.pathDG1 + "\t Path DG: "
					+ pp.pathDG2);
		}

	}

	public static void addTotalPathPairs(HashMap totalPathPairs,
			HashSet<PathPair> currentPathPairs) {
		for (PathPair pp : currentPathPairs) {
			if (totalPathPairs.containsKey(pp)) {
				int cnt = (int) totalPathPairs.get(pp);
				totalPathPairs.put(pp, new Integer(cnt + 1));
			} else {
				totalPathPairs.put(pp, new Integer(1));
			}

		}
	}

	public static void writeInFileTotalPathPairs(HashMap totalPathPairs) {

		FileWriter fstream;
		try {
			fstream = new FileWriter(Constants.projectDirectory
					+ "totalPairs.txt");

			BufferedWriter out = new BufferedWriter(fstream);

			Iterator it = totalPathPairs.entrySet().iterator();
			while (it.hasNext()) {
				Map.Entry pairs = (Entry) it.next();
				PathPair pp = (PathPair) pairs.getKey();
				int cnt = (int) pairs.getValue();
				float posibility =(float) cnt/(float)NumberofInputvalues;
				out.write(pp.pathDG1 + "\t\t" + pp.pathDG2 + "\t\t" + posibility+"\n");
			}
			out.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

	public static void main(String[] args) throws Exception {

		final long startTime = System.currentTimeMillis();

		HashMap<PathPair, Integer> totalPathPairs = new HashMap<PathPair, Integer>();
		try (BufferedReader br = new BufferedReader(new FileReader(
				Constants.fileWithInputsAndEntities))) {

			String sCurrentLine;
			while ((sCurrentLine = br.readLine()) != null) {
				NumberofInputvalues++;
				String[] columns = sCurrentLine.split("-->");

				GraphGuide graphG = new GraphGuide();
				graphG.parseInputsEntitiesFile(columns[1]);

				DataGuide dataG = new DataGuide();
				dataG.makeparse(Constants.pathToCallResults
						+ columns[0].replace(" ", "+"));

				OverlappingGuides ov = new OverlappingGuides(graphG, dataG,
						new GraphNode.NormalizeCompareMIX());
				addTotalPathPairs(totalPathPairs, ov.pathPairsSet);
				System.out.println("FINISH OVERLAPPING FOR "+ columns[0].replace(" ", "+"));
				
			}

		} catch (IOException e) {
			e.printStackTrace();
		}

		writeInFileTotalPathPairs(totalPathPairs);
		// ov.printPathPairsCount();
		// ov.checkPriorityQueues();

		System.out.println("NumberofInputvalues:"+NumberofInputvalues);
		final long endTime = System.currentTimeMillis();
		System.out.println("\n\n\nTotal execution time: "
				+ ((endTime - startTime) / 1000) /60);

		System.out.println(QueryYAGOTDB.queryCNT);

	}

}
